﻿using System;
using System.IO;
using AppLimit.CloudComputing.SharpBox;
using AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox;
using RuTracker.Interface.Dropbox;
using RuTrackerLib.ServiceAttibutes;

namespace RuTrackerLib.Storage
{
    [PerCallService]
    public class DropBoxAccessor : IDropBoxAccessor
    {
        private CloudStorage _dropBoxStorage;
        private bool _connected;

        public DropBoxAccessor()
        {
            _connected = false;
        }

        public void Connect(byte[] token)
        {
            if (token == null || token.Length == 0)
                throw new ArgumentException("token cannot be null or empty array");

            _dropBoxStorage = new CloudStorage();
            DropBoxConfiguration config = CloudStorage.GetCloudConfigurationEasy(nSupportedCloudConfigurations.DropBox) as DropBoxConfiguration;
            try
            {
                using (MemoryStream MS = new MemoryStream(token))
                {
                    MS.Position = 0;
                    ICloudStorageAccessToken accessToken = _dropBoxStorage.DeserializeSecurityToken(MS);
                    _dropBoxStorage.Open(config, accessToken);
                }
                _connected = true;
            }
            catch(Exception ex)
            {
                throw new DropBoxAccessException("Error during opening connection to storage account", ex);
            }

        }

        public void Disconnect()
        {
            _connected = false;
        }

        public void Dispose()
        {
            Disconnect();
        }

        /// <summary>
        /// Loads full storage hierarchy and returns it
        /// </summary>
        /// <returns></returns>
        public StorageFolder LoadHierarchy()
        {
            EnsureConnectionIsOpened();

            StorageFolder rootFolder = new StorageFolder(null, null);
            ICloudDirectoryEntry root = _dropBoxStorage.GetRoot();
            LoadFolder(root, rootFolder);

            return rootFolder;
        }

        /// <summary>
        /// Uploads file to a specific folder
        /// </summary>
        public void UploadFile(string fileName, StorageFolder destination, byte[] body)
        {
            EnsureConnectionIsOpened();

            ICloudDirectoryEntry dropBoxFolder = _dropBoxStorage.GetFolder(destination.FullName, false);
            if (dropBoxFolder == null)
                throw new DropBoxAccessException(string.Format("Cannot upload file: {0} to folder: '{1}', because folder doesn't exist", fileName, destination.FullName));

            try
            {
                using (MemoryStream MS = new MemoryStream(body))
                {
                    MS.Position = 0;
                    _dropBoxStorage.UploadFile(MS, fileName, dropBoxFolder);
                }
            }
            catch (Exception exception)
            {
                throw new DropBoxAccessException(string.Format("Cannot upload file: {0} to folder: '{1}' due to unexpected exception", fileName, destination.FullName), exception);
            }
        }

        /// <summary>
        /// Deletes item from storage
        /// </summary>
        public bool Delete(IStorageItem storageItem)
        {
            EnsureConnectionIsOpened();

            return _dropBoxStorage.DeleteFileSystemEntry(storageItem.FullName);
        }

        private void LoadFolder(ICloudDirectoryEntry folder, StorageFolder parentStorageFolder)
        {
            foreach (ICloudFileSystemEntry entry in folder)
            {
                if (entry is ICloudDirectoryEntry) //this is folder
                {
                    ICloudDirectoryEntry cloudFolder = (ICloudDirectoryEntry)entry;
                    StorageFolder childFolder = parentStorageFolder.AddFolder(entry.Name);
                    LoadFolder(cloudFolder, childFolder);
                }
                else //this is file
                {
                    parentStorageFolder.AddFile(entry.Name);
                }
            }
        }

        private void EnsureConnectionIsOpened()
        {
            if (!_connected)
                throw new DropBoxAccessException("Connection isn't opened");
        }
    }
}

